#!/usr/bin/python

import sys
from vgcvxopt import qp
from unique import unique
import getopt
import types

import acgt2wyk
import sample as mysample

# -- global --
global debug
global lowest_score
global lowest_scoring_sequence

def usage():
    print '''Usage : qp.py [options] [file]

    Options:
    --------
    -h, --help                   Display this text and exit.
    -d, --debug                  Show debugging info (intermediate matrices).
    -s, --sample                 Show samples instead of any matrix.
    -w, --wyk                    Show WYK matrix instead of ACGT matrix.
    -l, --lowest                 Show lowest scoring sequence above threshold and exit.
    '''

def main(argv):
    try:
        opts, args = getopt.getopt(argv, "hdswl", ["help", "debug", "sample", "wyk", "lowest"])
    except getopt.GetoptError:
        usage()
        sys.exit(2)

    global debug
    debug = False
    sample = 0
    wyk = 0
    lowest = 0
    
    for opt, arg in opts:
        if opt in ("-h", "--help"):
            usage()
            sys.exit()
        elif opt in ("-d", "--debug"):
            debug = True
        elif opt in ("-s", "--sample"):
            sample = 1
            #total_population = arg
        elif opt in ("-w", "--wyk"):
            wyk = 1
        elif opt in ("-l", "--lowest"):
            lowest = 1
            #total_population = arg
        else:
            usage()
            sys.exit()

    if (len(args) != 1):
        usage()
        sys.exit("Please specify file having samples.")


    # do all the initial processing
    # this program just handles a single file a time
    file = ''.join(args)
    lines = init(file)
    
    #if debug == 1:
    #    print "Frequency Matrix:"
    #    showMatrix(frequencyMatrix(lines))
    #    print "\nOccurence Matrix:"
    #    showMatrix(occurenceMatrix(lines))
        
    weight_mat = qp(file)
    wyk_mat = acgt2wyk.acgt2wyk(weight_mat)
    
    if (wyk == 1):
        showMatrix(wyk_mat)
    elif (sample == 1):
        total_population = mysample.main(['-t', lowestScore(lines, weight_mat)], weight_mat)
        showSamples(lines, weight_mat, total_population)
    elif (lowest == 1):
        total_population = mysample.main(['-t', lowestScore(lines, weight_mat)], weight_mat)
        showLowest(lines, weight_mat, total_population)
    else:
        showMatrix(weight_mat)

def init(filename):
    # open file having alignments
    file = open(filename, 'r')
    
    lines = file.readlines()
    
    for i in xrange(len(lines)):
        lines[i] = (lines[i]).strip()
        
    # return a list cotaining all the lines in given file
    return lines
                                

def showMatrix(weight_mat):
    for row in weight_mat:
        for col in row:
            if (type(col) == types.IntType):
                print col,
            elif (type(col) == types.FloatType):
                print '%.2f' % col,
            else:
                print "Matrix element type not supported."
                sys.exit(2)
        print

def showSamples(lines, weight_mat, total_population):
    global lowest_score
    global lowest_scoring_sequence
    global debug
    
    total_pop = total_population # all samples having given length
    min_score = score(lines[0], weight_mat)
    
    for line in lines:
        if score(line, weight_mat) < min_score:
            min_score = score(line, weight_mat)
            lowest_score = min_score
            lowest_scoring_sequence = line

    if debug:
        print "Min score :", min_score
    
    for line in total_pop:
        line_score = score(line, weight_mat)
        if line_score >= min_score:
            if debug:
                print line, line_score 
            else:
                print line

def showLowest(lines, weight_mat, total_population):
    total_pop = total_population # all samples having given length
    min_score = score(lines[0], weight_mat)

    lowest_score = min_score
    lowest_scoring_seq = lines[0]
    
    for line in lines:
        if score(line, weight_mat) < min_score:
            min_score = score(line, weight_mat)
            lowest_score = min_score
            lowest_scoring_seq = line

    print lowest_scoring_seq
            
def lowestScore(lines, weight_mat):
    min_score = score(lines[0], weight_mat)

    lowest_score = min_score
    
    for line in lines:
        if score(line, weight_mat) < min_score:
            min_score = score(line, weight_mat)
            lowest_score = min_score

    return lowest_score

def score(line, weight_mat):
    score = 0
    
    base_map = {'a':0, 'c':1, 'g':2, 't':3, 'A':0, 'C':1, 'G':2, 'T':3}
    
    for i in xrange(len(line)):
        score += weight_mat[base_map[line[i]]][i]
        
    return score

if __name__ == "__main__":
    main(sys.argv[1:])

